<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Complex Functions and Function Complexities</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Advanced Bash-Scripting Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Functions"
HREF="functions.html"><LINK
REL="PREVIOUS"
TITLE="Functions"
HREF="functions.html"><LINK
REL="NEXT"
TITLE="Local Variables"
HREF="localvar.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Advanced Bash-Scripting Guide: </TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="functions.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 24. Functions</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="localvar.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="COMPLEXFUNCT"
></A
>24.1. Complex Functions and Function Complexities</H1
><P
>Functions may process arguments passed to them and return
	an <A
HREF="exit-status.html#EXITSTATUSREF"
>exit status</A
> to the script
	for further processing.</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>function_name $arg1 $arg2</PRE
></FONT
></TD
></TR
></TABLE
><P
><A
NAME="PASSEDARGS"
></A
></P
><P
>The function refers to the passed arguments by position (as if they were
	<A
HREF="internalvariables.html#POSPARAMREF"
>positional parameters</A
>),
	that is, <TT
CLASS="VARNAME"
>$1</TT
>, <TT
CLASS="VARNAME"
>$2</TT
>, and
	so forth.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX60"
></A
><P
><B
>Example 24-2. Function Taking Parameters</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# Functions and parameters

DEFAULT=default                             # Default param value.

func2 () {
   if [ -z "$1" ]                           # Is parameter #1 zero length?
   then
     echo "-Parameter #1 is zero length.-"  # Or no parameter passed.
   else
     echo "-Parameter #1 is \"$1\".-"
   fi

   variable=${1-$DEFAULT}                   #  What does
   echo "variable = $variable"              #+ parameter substitution show?
                                            #  ---------------------------
                                            #  It distinguishes between
                                            #+ no param and a null param.

   if [ "$2" ]
   then
     echo "-Parameter #2 is \"$2\".-"
   fi

   return 0
}

echo
   
echo "Nothing passed."   
func2                          # Called with no params
echo


echo "Zero-length parameter passed."
func2 ""                       # Called with zero-length param
echo

echo "Null parameter passed."
func2 "$uninitialized_param"   # Called with uninitialized param
echo

echo "One parameter passed."   
func2 first           # Called with one param
echo

echo "Two parameters passed."   
func2 first second    # Called with two params
echo

echo "\"\" \"second\" passed."
func2 "" second       # Called with zero-length first parameter
echo                  # and ASCII string as a second one.

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
><A
NAME="FSHIFTREF"
></A
></P
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The <A
HREF="othertypesv.html#SHIFTREF"
>shift</A
>
        command works on arguments passed to functions (see <A
HREF="assortedtips.html#MULTIPLICATION"
>Example 36-18</A
>).</P
></TD
></TR
></TABLE
></DIV
><P
>But, what about command-line arguments passed to the script? 
        Does a function see them? Well, let's clear up the confusion.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="FUNCCMDLINEARG"
></A
><P
><B
>Example 24-3. Functions and command-line args passed to the script</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# func-cmdlinearg.sh
#  Call this script with a command-line argument,
#+ something like $0 arg1.


func ()

{
echo "$1"   # Echoes first arg passed to the function.
}           # Does a command-line arg qualify?

echo "First call to function: no arg passed."
echo "See if command-line arg is seen."
func
# No! Command-line arg not seen.

echo "============================================================"
echo
echo "Second call to function: command-line arg passed explicitly."
func $1
# Now it's seen!

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>In contrast to certain other programming languages,
	shell scripts normally pass only value parameters to
	functions. Variable names (which are actually
	<I
CLASS="FIRSTTERM"
>pointers</I
>), if
	passed as parameters to functions, will be treated as string
	literals.  <EM
>Functions interpret their arguments
	literally.</EM
></P
><P
><A
NAME="FUNCPOINTERS"
></A
></P
><P
><A
HREF="ivr.html#IVRREF"
>Indirect variable
	    references</A
> (see <A
HREF="bashver2.html#EX78"
>Example 37-2</A
>) provide a clumsy
	    sort of mechanism for passing variable pointers to
	    functions.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="INDFUNC"
></A
><P
><B
>Example 24-4. Passing an indirect reference to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# ind-func.sh: Passing an indirect reference to a function.

echo_var ()
{
echo "$1"
}

message=Hello
Hello=Goodbye

echo_var "$message"        # Hello
# Now, let's pass an indirect reference to the function.
echo_var "${!message}"     # Goodbye

echo "-------------"

# What happens if we change the contents of "hello" variable?
Hello="Hello, again!"
echo_var "$message"        # Hello
echo_var "${!message}"     # Hello, again!

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>The next logical question is whether parameters can be
	  dereferenced <EM
>after</EM
> being passed to a
	  function.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="DEREFERENCECL"
></A
><P
><B
>Example 24-5. Dereferencing a parameter passed to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# dereference.sh
# Dereferencing parameter passed to a function.
# Script by Bruce W. Clare.

dereference ()
{
     y=\$"$1"   # Name of variable (not value!).
     echo $y    # $Junk

     x=`eval "expr \"$y\" "`
     echo $1=$x
     eval "$1=\"Some Different Text \""  # Assign new value.
}

Junk="Some Text"
echo $Junk "before"    # Some Text before

dereference Junk
echo $Junk "after"     # Some Different Text after

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="REFPARAMS"
></A
><P
><B
>Example 24-6. Again, dereferencing a parameter passed to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# ref-params.sh: Dereferencing a parameter passed to a function.
#                (Complex Example)

ITERATIONS=3  # How many times to get input.
icount=1

my_read () {
  #  Called with my_read varname,
  #+ outputs the previous value between brackets as the default value,
  #+ then asks for a new value.

  local local_var

  echo -n "Enter a value "
  eval 'echo -n "[$'$1'] "'  #  Previous value.
# eval echo -n "[\$$1] "     #  Easier to understand,
                             #+ but loses trailing space in user prompt.
  read local_var
  [ -n "$local_var" ] &#38;&#38; eval $1=\$local_var

  # "And-list": if "local_var" then set "$1" to its value.
}

echo

while [ "$icount" -le "$ITERATIONS" ]
do
  my_read var
  echo "Entry #$icount = $var"
  let "icount += 1"
  echo
done  


# Thanks to Stephane Chazelas for providing this instructive example.

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="EXITRETURN1"
></A
>Exit and Return</B
></P
><DL
><DT
><B
CLASS="COMMAND"
>exit status</B
></DT
><DD
><P
>Functions return a value, called an <I
CLASS="FIRSTTERM"
>exit
	      status</I
>. This is analogous to the <A
HREF="exit-status.html#EXITSTATUSREF"
>exit status</A
> returned by a
	      command. The exit status may be explicitly specified
	      by a <B
CLASS="COMMAND"
>return</B
> statement, otherwise it
	      is the exit status of the last command in the function
	      (<SPAN
CLASS="RETURNVALUE"
>0</SPAN
> if successful, and a non-zero
	      error code if not). This <A
HREF="exit-status.html#EXITSTATUSREF"
>exit
	      status</A
> may be used in the script by referencing it
	      as <A
HREF="internalvariables.html#XSTATVARREF"
>$?</A
>.  This mechanism
	      effectively permits script functions to have a <SPAN
CLASS="QUOTE"
>"return
	      value"</SPAN
> similar to C functions.</P
></DD
><DT
><B
CLASS="COMMAND"
>return</B
></DT
><DD
><P
><A
NAME="RETURNREF"
></A
></P
><P
>Terminates a function. A <B
CLASS="COMMAND"
>return</B
> command
	       <A
NAME="AEN18474"
HREF="#FTN.AEN18474"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
>
	      optionally takes an <I
CLASS="FIRSTTERM"
>integer</I
>
	      argument, which is returned to the calling script as
	      the <SPAN
CLASS="QUOTE"
>"exit status"</SPAN
> of the function, and
	      this exit status is assigned to the variable <A
HREF="internalvariables.html#XSTATVARREF"
>$?</A
>.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="MAX"
></A
><P
><B
>Example 24-7. Maximum of two numbers</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# max.sh: Maximum of two integers.

E_PARAM_ERR=250    # If less than 2 params passed to function.
EQUAL=251          # Return value if both params equal.
#  Error values out of range of any
#+ params that might be fed to the function.

max2 ()             # Returns larger of two numbers.
{                   # Note: numbers compared must be less than 250.
if [ -z "$2" ]
then
  return $E_PARAM_ERR
fi

if [ "$1" -eq "$2" ]
then
  return $EQUAL
else
  if [ "$1" -gt "$2" ]
  then
    return $1
  else
    return $2
  fi
fi
}

max2 33 34
return_val=$?

if [ "$return_val" -eq $E_PARAM_ERR ]
then
  echo "Need to pass two parameters to the function."
elif [ "$return_val" -eq $EQUAL ]
  then
    echo "The two numbers are equal."
else
    echo "The larger of the two numbers is $return_val."
fi  

  
exit 0

#  Exercise (easy):
#  ---------------
#  Convert this to an interactive script,
#+ that is, have the script ask for input (two numbers).</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="TIP"
><P
></P
><TABLE
CLASS="TIP"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/tip.gif"
HSPACE="5"
ALT="Tip"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>For a function to return a string or array, use a
	      dedicated variable.
	        <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>count_lines_in_etc_passwd()
{
  [[ -r /etc/passwd ]] &#38;&#38; REPLY=$(echo $(wc -l &#60; /etc/passwd))
  #  If /etc/passwd is readable, set REPLY to line count.
  #  Returns both a parameter value and status information.
  #  The 'echo' seems unnecessary, but . . .
  #+ it removes excess whitespace from the output.
}

if count_lines_in_etc_passwd
then
  echo "There are $REPLY lines in /etc/passwd."
else
  echo "Cannot count lines in /etc/passwd."
fi  

# Thanks, S.C.</PRE
></FONT
></TD
></TR
></TABLE
>
	    </P
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="EX61"
></A
><P
><B
>Example 24-8. Converting numbers to Roman numerals</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash

# Arabic number to Roman numeral conversion
# Range: 0 - 200
# It's crude, but it works.

# Extending the range and otherwise improving the script is left as an exercise.

# Usage: roman number-to-convert

LIMIT=200
E_ARG_ERR=65
E_OUT_OF_RANGE=66

if [ -z "$1" ]
then
  echo "Usage: `basename $0` number-to-convert"
  exit $E_ARG_ERR
fi  

num=$1
if [ "$num" -gt $LIMIT ]
then
  echo "Out of range!"
  exit $E_OUT_OF_RANGE
fi  

to_roman ()   # Must declare function before first call to it.
{
number=$1
factor=$2
rchar=$3
let "remainder = number - factor"
while [ "$remainder" -ge 0 ]
do
  echo -n $rchar
  let "number -= factor"
  let "remainder = number - factor"
done  

return $number
       # Exercises:
       # ---------
       # 1) Explain how this function works.
       #    Hint: division by successive subtraction.
       # 2) Extend to range of the function.
       #    Hint: use "echo" and command-substitution capture.
}
   

to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?
to_roman $num 40 XL
num=$?
to_roman $num 10 X
num=$?
to_roman $num 9 IX
num=$?
to_roman $num 5 V
num=$?
to_roman $num 4 IV
num=$?
to_roman $num 1 I
# Successive calls to conversion function!
# Is this really necessary??? Can it be simplified?

echo

exit</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>See also <A
HREF="testbranch.html#ISALPHA"
>Example 11-29</A
>.</P
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The largest positive integer a function can return is
	      255. The <B
CLASS="COMMAND"
>return</B
> command is closely tied
	      to the concept of <A
HREF="exit-status.html#EXITSTATUSREF"
>exit
	      status</A
>, which accounts for this particular
	      limitation.  Fortunately, there are various <A
HREF="assortedtips.html#RVT"
>workarounds</A
> for those situations
	      requiring a large integer return value from a
	      function.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="RETURNTEST"
></A
><P
><B
>Example 24-9. Testing large return values in a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# return-test.sh

# The largest positive value a function can return is 255.

return_test ()         # Returns whatever passed to it.
{
  return $1
}

return_test 27         # o.k.
echo $?                # Returns 27.
  
return_test 255        # Still o.k.
echo $?                # Returns 255.

return_test 257        # Error!
echo $?                # Returns 1 (return code for miscellaneous error).

# =========================================================
return_test -151896    # Do large negative numbers work?
echo $?                # Will this return -151896?
                       # No! It returns 168.
#  Version of Bash before 2.05b permitted
#+ large negative integer return values.
#  It happened to be a useful feature.
#  Newer versions of Bash unfortunately plug this loophole.
#  This may break older scripts.
#  Caution!
# =========================================================

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>A workaround for obtaining large integer <SPAN
CLASS="QUOTE"
>"return
	      values"</SPAN
> is to simply assign the <SPAN
CLASS="QUOTE"
>"return
	      value"</SPAN
> to a global variable.

	        <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>Return_Val=   # Global variable to hold oversize return value of function.

alt_return_test ()
{
  fvar=$1
  Return_Val=$fvar
  return   # Returns 0 (success).
}

alt_return_test 1
echo $?                              # 0
echo "return value = $Return_Val"    # 1

alt_return_test 256
echo "return value = $Return_Val"    # 256

alt_return_test 257
echo "return value = $Return_Val"    # 257

alt_return_test 25701
echo "return value = $Return_Val"    #25701</PRE
></FONT
></TD
></TR
></TABLE
>
            </P
><P
><A
NAME="CAPTURERETVAL"
></A
></P
><P
>A more elegant method is to have the function
              <B
CLASS="COMMAND"
>echo</B
> its <SPAN
CLASS="QUOTE"
>"return
              value to <TT
CLASS="FILENAME"
>stdout</TT
>,"</SPAN
> and
              then capture it by <A
HREF="commandsub.html#COMMANDSUBREF"
>command
	      substitution</A
>. See the <A
HREF="assortedtips.html#RVT"
>discussion
	      of this</A
> in <A
HREF="assortedtips.html"
>Section 36.7</A
>.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="MAX2"
></A
><P
><B
>Example 24-10. Comparing two large integers</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# max2.sh: Maximum of two LARGE integers.

#  This is the previous "max.sh" example,
#+ modified to permit comparing large integers.

EQUAL=0             # Return value if both params equal.
E_PARAM_ERR=-99999  # Not enough params passed to function.
#           ^^^^^^    Out of range of any params that might be passed.

max2 ()             # "Returns" larger of two numbers.
{
if [ -z "$2" ]
then
  echo $E_PARAM_ERR
  return
fi

if [ "$1" -eq "$2" ]
then
  echo $EQUAL
  return
else
  if [ "$1" -gt "$2" ]
  then
    retval=$1
  else
    retval=$2
  fi
fi

echo $retval        # Echoes (to stdout), rather than returning value.
                    # Why?
}


return_val=$(max2 33001 33997)
#            ^^^^             Function name
#                 ^^^^^ ^^^^^ Params passed
#  This is actually a form of command substitution:
#+ treating a function as if it were a command,
#+ and assigning the stdout of the function to the variable "return_val."


# ========================= OUTPUT ========================
if [ "$return_val" -eq "$E_PARAM_ERR" ]
  then
  echo "Error in parameters passed to comparison function!"
elif [ "$return_val" -eq "$EQUAL" ]
  then
    echo "The two numbers are equal."
else
    echo "The larger of the two numbers is $return_val."
fi
# =========================================================
  
exit 0

#  Exercises:
#  ---------
#  1) Find a more elegant way of testing
#+    the parameters passed to the function.
#  2) Simplify the if/then structure at "OUTPUT."
#  3) Rewrite the script to take input from command-line parameters.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>Here is another example of capturing a function
	      <SPAN
CLASS="QUOTE"
>"return value."</SPAN
> Understanding it requires some
	      knowledge of <A
HREF="awk.html#AWKREF"
>awk</A
>.

	    <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>month_length ()  # Takes month number as an argument.
{                # Returns number of days in month.
monthD="31 28 31 30 31 30 31 31 30 31 30 31"  # Declare as local?
echo "$monthD" | awk '{ print $'"${1}"' }'    # Tricky.
#                             ^^^^^^^^^
# Parameter passed to function  ($1 -- month number), then to awk.
# Awk sees this as "print $1 . . . print $12" (depending on month number)
# Template for passing a parameter to embedded awk script:
#                                 $'"${script_parameter}"'

#    Here's a slightly simpler awk construct:
#    echo $monthD | awk -v month=$1 '{print $(month)}'
#    Uses the -v awk option, which assigns a variable value
#+   prior to execution of the awk program block.
#    Thank you, Rich.

#  Needs error checking for correct parameter range (1-12)
#+ and for February in leap year.
}

# ----------------------------------------------
# Usage example:
month=4        # April, for example (4th month).
days_in=$(month_length $month)
echo $days_in  # 30
# ----------------------------------------------</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>See also <A
HREF="contributed-scripts.html#DAYSBETWEEN"
>Example A-7</A
>
	      and <A
HREF="contributed-scripts.html#STDDEV"
>Example A-37</A
>.</P
><P
><TT
CLASS="USERINPUT"
><B
>Exercise:</B
></TT
> Using what we have
	      just learned, extend the previous <A
HREF="complexfunct.html#EX61"
>Roman numerals example</A
> to accept
	      arbitrarily large input.</P
></TD
></TR
></TABLE
></DIV
></DD
></DL
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="REDSTDINFUNC1"
></A
>Redirection</B
></P
><DL
><DT
><TT
CLASS="REPLACEABLE"
><I
>Redirecting the stdin
	    of a function</I
></TT
></DT
><DD
><P
>A function is essentially a <A
HREF="special-chars.html#CODEBLOCKREF"
>code block</A
>, which means its
	      <TT
CLASS="FILENAME"
>stdin</TT
> can be redirected (as in <A
HREF="special-chars.html#EX8"
>Example 3-1</A
>).</P
><DIV
CLASS="EXAMPLE"
><A
NAME="REALNAME"
></A
><P
><B
>Example 24-11. Real name from username</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# realname.sh
#
# From username, gets "real name" from /etc/passwd.


ARGCOUNT=1       # Expect one arg.
E_WRONGARGS=85

file=/etc/passwd
pattern=$1

if [ $# -ne "$ARGCOUNT" ]
then
  echo "Usage: `basename $0` USERNAME"
  exit $E_WRONGARGS
fi  

file_excerpt ()    #  Scan file for pattern,
{                  #+ then print relevant portion of line.
  while read line  # "while" does not necessarily need [ condition ]
  do
    echo "$line" | grep $1 | awk -F":" '{ print $5 }'
    # Have awk use ":" delimiter.
  done
} &#60;$file  # Redirect into function's stdin.

file_excerpt $pattern

# Yes, this entire script could be reduced to
#       grep PATTERN /etc/passwd | awk -F":" '{ print $5 }'
# or
#       awk -F: '/PATTERN/ {print $5}'
# or
#       awk -F: '($1 == "username") { print $5 }' # real name from username
# However, it might not be as instructive.

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>There is an alternate, and perhaps less confusing
	     method of redirecting a function's
	     <TT
CLASS="FILENAME"
>stdin</TT
>.  This involves redirecting the
	     <TT
CLASS="FILENAME"
>stdin</TT
> to an embedded bracketed code
	     block within the function.

	       <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
># Instead of:
Function ()
{
 ...
 } &#60; file

# Try this:
Function ()
{
  {
    ...
   } &#60; file
}

# Similarly,

Function ()  # This works.
{
  {
   echo $*
  } | tr a b
}

Function ()  # This doesn't work.
{
  echo $*
} | tr a b   # A nested code block is mandatory here.


# Thanks, S.C.</PRE
></FONT
></TD
></TR
></TABLE
>
           </P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>Emmanuel Rouat's <A
HREF="sample-bashrc.html"
>sample <TT
CLASS="FILENAME"
>bashrc</TT
>
             file</A
> contains some instructive examples of
             functions.</P
></TD
></TR
></TABLE
></DIV
></DD
></DL
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN18474"
HREF="complexfunct.html#AEN18474"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>The <B
CLASS="COMMAND"
>return</B
> command is a
		 Bash <A
HREF="internal.html#BUILTINREF"
>builtin</A
>.</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="functions.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="localvar.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Functions</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="functions.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Local Variables</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>